package com.tbit.uqbike.protocol.AnalyzeImpl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tbit.uqbike.protocol.ABaseHandleObj;
import com.tbit.uqbike.protocol.ATerPkg;
import com.tbit.uqbike.tergateway.data.TerGatewayData;
import com.tbit.uqbike.tergateway.entity.AConnInfo;
import com.tbit.uqbike.tergateway.entity.RemoteControl;
import com.tbit.uqbike.tergateway.wa205pkg.*;
import com.tbit.uqbike.util.CharsetName;
import com.tbit.uqbike.util.ConstDefine;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by MyWin on 2018/5/16 0016.
 */
public class WA205DeEnCoder extends AProtocol {
    private static Logger logger = LoggerFactory.getLogger(WA205DeEnCoder.class);
    public static final String protocolName = "WA205";

    static {
        //AAutoProtocol.regProtocol(new WA205DeEnCoder());
    }

    @Override
    public List<ATerPkg> analyzeTerPkg(AConnInfo conn, ByteBuf in) {
        List<ATerPkg> list = new LinkedList<>();
        int pkgLen;
        while (in.readableBytes() >= 3) {
            // 先判定第三个字符是不是括号
            short startByte = in.getUnsignedByte(2);
            if (startByte == '{') {
                // 获取长度
                pkgLen = in.getUnsignedShort(0);
                if (in.readableBytes() > 2 + pkgLen - 1) {
                    // 判定是不是括号反括
                    short endByte = in.getUnsignedByte(2 + pkgLen - 1);
                    if (endByte == '}') {
                        pkgLen = in.readUnsignedShort();
                        byte[] data = new byte[pkgLen];
                        in.readBytes(data);
                        try {
                            String str = new String(data, 0, data.length, CharsetName.US_ASCII);
                            ATerPkg pkg = analyzePkg(str, data);
                            if (null != pkg) {
                                pkg.setConnId(conn.connId);
                                pkg.setProName(getProtocolName());
                                if (pkg.autoRsp()) {
                                    ByteBuf rsp = pkg.getRsp(conn, AAutoProtocol.getProtocol(protocolName));
                                    if (null != rsp && rsp.readableBytes() > 0) {
                                        conn.downMsg(rsp);
                                    }
                                }
                                list.add(pkg);
                            }
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    } else {
                        // 跳过一个字节 继续尝试解析
                        in.skipBytes(1);
                    }
                } else {
                    // 数据不够继续等待 跳出解析
                    break;
                }
            } else {
                // 跳过一个字节 继续尝试解析
                in.skipBytes(1);
            }
        }
        return list;
    }

    private ATerPkg analyzePkg(String str, byte[] bs) {
        logger.debug(String.format("Recv:%s", str));
        // 各种类型的报文判定
        ATerPkg pkg = null;
        if (str == null || str.isEmpty()) {
            return pkg;
        }
        try {
            JSONObject jsonObject = JSONObject.parseObject(str);
            if (jsonObject != null) {
                // 根据关键字来判断是什么报文
                // {"sn":"021002727","lon":"","lat":"","safeStatus":"1","batvol":"0.00"}
                if (jsonObject.containsKey("sn")) {
                    // 区分登录、位置、心跳、控制器、告警
                    if (jsonObject.containsKey("func")) {
                        Login login = new Login();
                        login.sn = jsonObject.getString("sn");
                        login.updateMno(login.sn);
                        login.lon = jsonObject.getString("lon");
                        login.lat = jsonObject.getString("lat");
                        login.safeStatus = jsonObject.getString("safeStatus");
                        login.batvol = jsonObject.getString("batvol");
                        login.func = jsonObject.getString("func");
                        login.rebootErr = jsonObject.getString("rebootErr");
                        pkg = login;
                    }
                    //{"sn":"022014038","time":0,"mileage":500,"singlemileage":250,"speed":215,"error":0,"vol":360,"cur":50,"bat":12000}
                    //控制器报文
                    else if (jsonObject.containsKey("mileage")) {
                        ControlInfo controlInfo = new ControlInfo();
                        controlInfo.time = jsonObject.getInteger("time");
                        controlInfo.sn = jsonObject.getString("sn");
                        controlInfo.updateMno(controlInfo.sn);
                        controlInfo.mileage = jsonObject.getInteger("mileage");
                        controlInfo.singlemileage = jsonObject.getInteger("singlemileage");
                        controlInfo.speed = jsonObject.getInteger("speed");
                        controlInfo.error = jsonObject.getInteger("error");
                        controlInfo.vol = jsonObject.getInteger("vol");
                        controlInfo.cur = jsonObject.getInteger("cur");
                        controlInfo.bat = jsonObject.getInteger("bat");
                        pkg = controlInfo;
                    }
                    //{"sn":"022014038","time":0,"mileage":500,"singlemileage":250,"speed":215,"error":0,"vol":360,"cur":50,"bat":12000}
                    //告警报文
                    else if (jsonObject.containsKey("alarm")) {
                        Alarm alarm = new Alarm();
                        alarm.sn = jsonObject.getString("sn");
                        alarm.updateMno(alarm.sn);
                        alarm.lon = jsonObject.getString("lon");
                        alarm.lat = jsonObject.getString("lat");
                        alarm.safeStatus = jsonObject.getString("safeStatus");
                        alarm.batvol = jsonObject.getString("batvol");
                        alarm.alarm = jsonObject.getString("alarm");
                        pkg = alarm;
                    } else if (jsonObject.containsKey("lon")) {
                        // 有经纬度的位置
                        if (!jsonObject.getString("lon").isEmpty()) {
                            Pos pos = new Pos();
                            pos.sn = jsonObject.getString("sn");
                            pos.updateMno(pos.sn);
                            pos.lon = jsonObject.getString("lon");
                            pos.lat = jsonObject.getString("lat");
                            pos.safeStatus = jsonObject.getString("safeStatus");
                            pos.batvol = jsonObject.getString("batvol");
                            pkg = pos;
                        }
                        // 心跳
                        else {
                            Heart heart = new Heart();
                            heart.sn = jsonObject.getString("sn");
                            heart.updateMno(heart.sn);
                            heart.lon = jsonObject.getString("lon");
                            heart.lat = jsonObject.getString("lat");
                            heart.safeStatus = jsonObject.getString("safeStatus");
                            heart.batvol = jsonObject.getString("batvol");
                            pkg = heart;
                        }
                    }
                }
                // {"result":"200","msgId":"6e5b8c4a508047a4a9a84a164de7c6d6"}
                else if (jsonObject.containsKey("result")) {
                    TerControlRsp tcr = new TerControlRsp();
                    tcr.msgId = jsonObject.getString("msgId");
                    tcr.result = jsonObject.getString("result");
                    pkg = tcr;
                }
                // 查询
                else if (jsonObject.containsKey("msgId") && jsonObject.containsKey("paramvalue")) {
                    TerParamConfigRsp tpcr = new TerParamConfigRsp();
                    tpcr.msgId = jsonObject.getString("msgId");
                    tpcr.paramvalue = jsonObject.getString("paramvalue");
                    pkg = tpcr;
                }
                // 设置
                else if (jsonObject.containsKey("msgId") && jsonObject.containsKey("paramret")) {
                    TerParamConfigRsp tpcr = new TerParamConfigRsp();
                    tpcr.msgId = jsonObject.getString("msgId");
                    tpcr.paramret = jsonObject.getString("paramret");
                    pkg = tpcr;
                }
                if (null != pkg) {
                    pkg.signPkg = bs;
                }
            }
        } catch (Exception e) {
            logger.error("analyzePkg", e);
        }
        return pkg;
    }

    @Override
    public ByteBuf builtRemoteControlPkg(AConnInfo conn, ABaseHandleObj aBaseHandleObj) {
        ByteBuf byteBuf = null;
        RemoteControl remoteControl = (RemoteControl) aBaseHandleObj;
        try {
            if (ConstDefine.CONTROL_TYPE_GET.equals(remoteControl.controlType)) {
                byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
                TerParamConfig tpc = new TerParamConfig();
                tpc.msgId = remoteControl.serNO;
                tpc.opname = Wa205Def.OP_GET;
                // 去掉分号
                remoteControl.paramName = remoteControl.paramName.replace(";", "");
                tpc.paramname = remoteControl.paramName;
                writeDownBytes(byteBuf, tpc);
            } else if (ConstDefine.CONTROL_TYPE_SET.equals(remoteControl.controlType)) {
                byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
                TerParamConfig tpc = new TerParamConfig();
                tpc.msgId = remoteControl.serNO;
                tpc.opname = Wa205Def.OP_SET;
                // 去掉分号
                remoteControl.paramName = remoteControl.paramName.replace(";", "");
                String[] params = remoteControl.paramName.split("=");
                tpc.paramname = params[0];
                tpc.paramvalue = params[1];
                writeDownBytes(byteBuf, tpc);
            } else if (ConstDefine.CONTROL_TYPE_CONTROL.equals(remoteControl.controlType)) {
                // 只支持部分
                Integer code = Integer.parseInt(remoteControl.paramName);
                if (code == 0x1) {
                    code = 304;
                } else if (code == 0x02) {
                    code = 302;
                } else if (code == 0x0B) {
                    code = 301;
                } else if (code == 0x0c) {
                    code = 305;
                } else if (code == 0x0f) {
                    code = 306;
                } else if (code == 0x10) {
                    code = 307;
                }
                if (code >= 300) {
                    byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
                    TerControl tc = new TerControl();
                    tc.msgId = remoteControl.serNO;
                    tc.code = code.toString();
                    writeDownBytes(byteBuf, tc);
                }
            } else if (ConstDefine.CONTROL_TYPE_VOICE.equals(remoteControl.controlType)) {
                byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
                VoiceControl vc = new VoiceControl();
                vc.msgId = remoteControl.serNO;
                vc.voiceId = remoteControl.paramName;
                writeDownBytes(byteBuf, vc);
            } else {
                logger.error(String.format("构造下行数据包异常,未知的指令类型:[%s]", remoteControl.controlType));
                return null;
            }
            // 创建完成 写入全局缓存
            if (null != byteBuf) {
                TerGatewayData.setStrSerNoMap(remoteControl.serNO, remoteControl);
                return byteBuf;
            }
        } catch (Exception e) {
            if (byteBuf != null) {
                byteBuf.clear();
            }
            logger.error("构造下行数据包异常", e);
        }
        return null;
    }

    @Override
    public String getProtocolName() {
        return protocolName;
    }

    public static void writeDownBytes(ByteBuf byteBuf, Object obj) {
        String str = JSON.toJSONString(obj);
        try {
            byte[] bs = str.getBytes(CharsetName.US_ASCII);
            byteBuf.writeShort(bs.length);
            byteBuf.writeBytes(bs);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public static void getCommRsp(ByteBuf byteBuf, String result) {
        CommRsp rsp = new CommRsp();
        rsp.result = result;
        writeDownBytes(byteBuf, rsp);
    }
}
